package ym.ecrm.core.dao.base.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import ym.ecrm.core.common.util.Assert;
import ym.ecrm.core.common.util.Pager;
import ym.ecrm.core.dao.base.IEntityDAO;

/**
 * 数据操作基类
 * 
 * @author Princess
 * @version 1.0
 */
@SuppressWarnings("unchecked")
public class HibernateEntityDAO<T> implements IEntityDAO<T>{

	private Class<T> entityClass;
	
	@Autowired
	protected  HibernateTemplate hibernateTemplate;
	
	//得到泛型T的实例
	public HibernateEntityDAO() {
		entityClass = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@Override
	public List<T> findBy(final String propertyName, final Object value) {
		return findBy(propertyName, value, null, true);
	}

	@Override
	public List<T> findBy(final String propertyName, final Object value,
			final String orderBy, final boolean isAsc) {
		List<T> list = getHibernateTemplate().executeFind(
				new HibernateCallback<List<T>>() {
					@Override
					public List<T> doInHibernate(Session session)
							throws HibernateException, SQLException {
						String hql = "from " + entityClass.getSimpleName()
								+ " where " + propertyName + "=:value";
						if(orderBy != null){
							if (isAsc) {
								hql = hql + " order by " + orderBy + " asc";
							} else {
								hql = hql + " order by " + orderBy + " desc";
							}
						}
						Query query = session.createQuery(hql);
						query.setParameter("value", value);
						return (List<T>) query.list();
					}
				});
		return list;
	}

	@Override
	public T findUniqueBy(final String propertyName, final Object value) {
		T t = getHibernateTemplate().execute(new HibernateCallback<T>() {
			@Override
			public T doInHibernate(Session session) throws HibernateException,
					SQLException {
				String hql = "from " + entityClass.getSimpleName() + " where "
						+ propertyName + "=:value";
				Query query = session.createQuery(hql);
				query.setParameter("value", value);
				List<T> list = query.list();
				if (list != null && !list.isEmpty()) {
					return (T) list.get(0);
				} else {
					return null;
				}
			}
		});
		return t;
	}

	@Override
	public void delete(T entity) {
		getHibernateTemplate().delete(entity);
	}

	@Override
	public void deleteAll() {
		getHibernateTemplate().deleteAll(getHibernateTemplate().loadAll(entityClass));
	}

	@Override
	public void delete(Collection<T> entities) {
		getHibernateTemplate().deleteAll(entities);
	}

	@Override
	public void save(T entity) {
		getHibernateTemplate().save(entity);
	}

	@Override
	public void update(T entity) {
		getHibernateTemplate().update(entity);
	}

	@Override
	public void update(Collection<T> entities) {
		Iterator<T> iterator = entities.iterator();
		while (iterator.hasNext()) {
			T t = (T) iterator.next();
			getHibernateTemplate().update(t);
		}
	}
	
	@Override
	public T load(Serializable id) {
		return this.getHibernateTemplate().load(entityClass, id);
	}

	@Override
	public T get(Serializable id) {
		return this.getHibernateTemplate().get(entityClass, id);
	}

	@Override
	public List<T> loadAll() {
		return this.getHibernateTemplate().loadAll(entityClass);
	}

	@Override
	public List find(String hql) {
		return this.getHibernateTemplate().find(hql);
	}

	@Override
	public List find(String hql, Object... params) {
		return this.getHibernateTemplate().find(hql,params);
	}

	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}

	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	@Override
	public List<T> fuzzyQuery(String propertyName, Object value) {
		return fuzzyQuery(propertyName, value, null, true);
	}

	@Override
	public List<T> fuzzyQuery(final String propertyName, final Object value,
			final String orderBy, final boolean isAsc) {
		List<T> list = getHibernateTemplate().executeFind(new HibernateCallback<List<T>>() {

			@Override
			public List<T> doInHibernate(Session session)
					throws HibernateException, SQLException {
				String hql = "from " + entityClass.getSimpleName()
					+ " where " + propertyName + " like :value";
				if(orderBy != null){
					if (isAsc) {
						hql = hql + " order by " + orderBy + " asc";
					} else {
						hql = hql + " order by " + orderBy + " desc";
					}
				}
				Query query = session.createQuery(hql);
				query.setParameter("value", "%"+value+"%");
				return query.list();
			}
		
		});
		return list;
	}

	@Override
	public void delete(final Serializable id) {
		T t = (T)get(id);
		getHibernateTemplate().delete(t);
	} 
	
	@Override
	public void flush(){
		getHibernateTemplate().flush();
	}
	
	public Pager pageQuery(String hql, int pageNo, int pageSize, Object...values){
		Assert.hasText(hql,"hql语句为null");
		Assert.isTure(pageNo >= 1, "查询的页码pageNo为null");
		
		String countQueryString = "select count(*)" + removeSelect(removeOrderby(hql));
		List countlist = getHibernateTemplate().find(countQueryString, values);
		long totalCount = (Long)countlist.get(0);
		
		if(totalCount < 1){
			return null;
		}
		
		int startIndex = Pager.getStartIndex(pageNo, pageSize);
		Query query = createQuery(hql, values);
		List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		return new Pager(pageNo,pageSize,totalCount,list);
	}
	
	public Query createQuery(String hql, Object...values){
		Assert.hasText(hql, "hql语句为null");
		Query query = getHibernateTemplate().getSessionFactory()
			.getCurrentSession().createQuery(hql);
		for(int i = 0; i < values.length; i++){
			query.setParameter(i, values[i]);
		}
		return query;
	}

	private static String removeSelect(String hql) {
		Assert.hasText(hql, "hql语句为null");
		int beginPos = hql.toLowerCase().indexOf("from");
		Assert.isTure(beginPos != -1, "hql:"+hql+" must has a keyword from");
		return hql.substring(beginPos);
	}

	private static String removeOrderby(String hql) {
		Assert.hasText(hql, "hql语句为null");
		Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*",Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		StringBuffer buf = new StringBuffer();
		while(m.find()){
			m.appendReplacement(buf, "");
		}
		m.appendTail(buf);
		return buf.toString();
	}
}
